from sysreptor.utils.fielddefinition.types import (
    BooleanField,
    CvssField,
    DateField,
    EnumChoice,
    EnumField,
    FieldDefinition,
    FieldOrigin,
    ListField,
    MarkdownField,
    ObjectField,
    StringField,
    UserField,
    serialize_field_definition,
)

# Core fields are the minimum required fields
# These fields are required internally and cannot be removed or changed
FINDING_FIELDS_CORE = FieldDefinition(fields=[
    StringField(id='title', origin=FieldOrigin.CORE, label='Title', spellcheck=True, default='TODO: Finding Title'),
])
# Prdefined fields are a set of fields which
FINDING_FIELDS_PREDEFINED = FieldDefinition(fields=[
    CvssField(id='cvss', origin=FieldOrigin.PREDEFINED, label='CVSS', default='n/a'),
    MarkdownField(id='summary', origin=FieldOrigin.PREDEFINED, label='Summary', required=True, default='TODO: High-level summary'),
    MarkdownField(id='description', origin=FieldOrigin.PREDEFINED, label='Technical Description', required=True, default='TODO: detailed technical description what this findings is about and how it can be exploited'),
    StringField(id='precondition', origin=FieldOrigin.PREDEFINED, label='Precondition', required=True, spellcheck=True, default=None),
    MarkdownField(id='impact', origin=FieldOrigin.PREDEFINED, label='Impact', required=True, default='TODO: impact of finding'),
    MarkdownField(id='recommendation', origin=FieldOrigin.PREDEFINED, label='Recommendation', required=True, default='TODO: how to fix the vulnerability'),
    StringField(id='short_recommendation', origin=FieldOrigin.PREDEFINED, label='Short Recommendation', required=True, spellcheck=True, default='TODO: short recommendation'),
    ListField(id='references', origin=FieldOrigin.PREDEFINED, label='References', required=False,
        items=StringField(origin=FieldOrigin.PREDEFINED, label='Reference', default=None)),
    ListField(id='affected_components', origin=FieldOrigin.PREDEFINED, label='Affected Components', required=True,
        items=StringField(origin=FieldOrigin.PREDEFINED, label='Component', default='TODO: affected component')),
    EnumField(id='owasp_top10_2021', origin=FieldOrigin.PREDEFINED, label='OWASP Top 10 - 2021', required=True, default=None, choices=[
        EnumChoice(value='A01_2021', label='A01:2021 - Broken Access Control'),
        EnumChoice(value='A02_2021', label='A02:2021 - Cryptographic Failures'),
        EnumChoice(value='A03_2021', label='A03:2021 - Injection'),
        EnumChoice(value='A04_2021', label='A04:2021 - Insecure Design'),
        EnumChoice(value='A05_2021', label='A05:2021 - Security Misconfiguration'),
        EnumChoice(value='A06_2021', label='A06:2021 - Vulnerable and Outdated Components'),
        EnumChoice(value='A07_2021', label='A07:2021 - Identification and Authentication Failures'),
        EnumChoice(value='A08_2021', label='A08:2021 - Software and Data Integrity Failures'),
        EnumChoice(value='A09_2021', label='A09:2021 - Security Logging and Monitoring Failures'),
        EnumChoice(value='A10_2021', label='A10:2021 - Server-Side Request Forgery (SSRF)'),
    ]),
    EnumField(id='wstg_category', origin=FieldOrigin.PREDEFINED, label='OWASP Web Security Testing Guide Category', required=True, default=None, choices=[
        EnumChoice(value='INFO', label='INFO - Information Gathering'),
        EnumChoice(value='CONF', label='CONF - Configuration and Deployment Management'),
        EnumChoice(value='IDNT', label='IDNT - Identity Management'),
        EnumChoice(value='ATHN', label='ATHN - Authentication'),
        EnumChoice(value='ATHZ', label='ATHZ - Authorization'),
        EnumChoice(value='SESS', label='SESS - Session Management'),
        EnumChoice(value='INPV', label='INPV - Input Validation'),
        EnumChoice(value='ERRH', label='ERRH - Error Handling'),
        EnumChoice(value='CRYP', label='CRYP - Weak Cryptography'),
        EnumChoice(value='BUSL', label='BUSL - Business Logic'),
        EnumChoice(value='CLNT', label='CLNT - Client-side Testing'),
        EnumChoice(value='APIT', label='APIT - API Testing'),
    ]),
    EnumField(id='severity', origin=FieldOrigin.PREDEFINED, label='Severity', required=True, default=None, choices=[
        EnumChoice(value='info', label='Info'),
        EnumChoice(value='low', label='Low'),
        EnumChoice(value='medium', label='Medium'),
        EnumChoice(value='high', label='High'),
        EnumChoice(value='critical', label='Critical'),
    ]),

    MarkdownField(id='retest_notes', origin=FieldOrigin.PREDEFINED, label='Re-test Notes', required=False, default=None),
    EnumField(id='retest_status', origin=FieldOrigin.PREDEFINED, label='Re-test Status', required=False, default=None, choices=[
        EnumChoice(value='open', label='Open'),
        EnumChoice(value='resolved', label='Resolved'),
        EnumChoice(value='partial', label='Partially Resolved'),
        EnumChoice(value='changed', label='Changed'),
        EnumChoice(value='accepted', label='Accepted'),
        EnumChoice(value='new', label='New'),
    ]),
])

REPORT_FIELDS_CORE = FieldDefinition(fields=[
    StringField(id='title', origin=FieldOrigin.CORE, label='Title', required=True, spellcheck=True, default='TODO: Report Title'),
])
REPORT_FIELDS_PREDEFINED = FieldDefinition(fields=[
    BooleanField(id='is_retest', origin=FieldOrigin.PREDEFINED, label='Is Retest', default=False),
])


def finding_fields_default():
    return serialize_field_definition(FieldDefinition(fields=[
        *FINDING_FIELDS_CORE.fields,
        *[FINDING_FIELDS_PREDEFINED[f] for f in ['cvss', 'affected_components', 'summary']],
        StringField(id='short_recommendation', label='Short Recommendation', required=True, default='TODO: short recommendation'),
        *[FINDING_FIELDS_PREDEFINED[f] for f in ['description', 'impact', 'recommendation', 'references']],
    ]))


def finding_ordering_default():
    return [
        {'field': 'cvss', 'order': 'desc'},
        {'field': 'title', 'order': 'asc'},
    ]


def report_sections_default():
    return [
        {
            'id': 'executive_summary',
            'label': 'Executive Summary',
            'fields': serialize_field_definition(FieldDefinition(fields=[
                MarkdownField(id='executive_summary', label='Executive Summary', required=True, default='**TODO: write executive summary**'),
            ])),
        },
        {
            'id': 'scope',
            'label': 'Scope',
            # 'fields': ['scope', 'duration', 'start_date', 'end_date'],
            'fields': serialize_field_definition(FieldDefinition(fields=[
                MarkdownField(id='scope', label='Scope', required=True, default='TODO: The scope of this pentest included:\n* Active Directory Domain xyz\n* Internal server network 10.20.30.40/24'),
                StringField(id='duration', label='Duration', required=True, default='TODO person days'),
                DateField(id='start_date', label='Pentest Start Date', required=True, default=None),
                DateField(id='end_date', label='Pentest End Date', required=True, default=None),
            ])),
        },
        {
            'id': 'customer',
            'label': 'Customer',
            'fields': serialize_field_definition(FieldDefinition(fields=[
                StringField(id='customer', label='Customer', required=True, default='TODO company'),
            ])),
        },
        # Other fields not defined elsewhere are put in the "other" section
        {
            'id': 'other',
            'label': 'Other',
            'fields': serialize_field_definition(REPORT_FIELDS_CORE | FieldDefinition(fields=[
                ListField(id='document_history', label='Document History', required=True, items=ObjectField(properties=[
                    StringField(id='version', label='Version', required=True, default='TODO: 1.0'),
                    DateField(id='date', label='Date', required=True, default=None),
                    StringField(id='description', label='Description', required=True, default='TODO: description'),
                    ListField(id='authors', label='Authors', required=True, items=UserField(required=True)),
                ])),
            ])),
        },
    ]
